home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / wincap.zip / DIBUTIL.C < prev    next >
C/C++ Source or Header  |  1991-11-05  |  19KB  |  679 lines

  1. /*
  2.  *  dibutil.c
  3.  *
  4.  *  Source file for Device-Independent Bitmap (DIB) API.  Provides
  5.  *  the following functions:
  6.  *
  7.  *  FindDIBBits()       - Sets pointer to the DIB bits
  8.  *  DIBWidth()          - Gets the width of the DIB
  9.  *  DIBHeight()         - Gets the height of the DIB
  10.  *  PaletteSize()       - Calculates the buffer size required by a palette
  11.  *  DIBNumColors()      - Calculates number of colors in the DIB's color table
  12.  *  CreateDIBPalette()  - Creates a palette from a DIB
  13.  *  DIBToBitmap()       - Creates a bitmap from a DIB
  14.  *  BitmapToDIB()       - Creates a DIB from a bitmap
  15.  *
  16.  * Development Team: Mark Bader
  17.  *                   Patrick Schreiber
  18.  *                   Garrett Mcauliffe
  19.  *                   Eric Flo
  20.  *                   Tony Claflin
  21.  *
  22.  * Written by Microsoft Product Support Services, Developer Support.
  23.  * Copyright (c) 1991 Microsoft Corporation. All rights reserved.
  24.  */
  25.  
  26. /* header files */
  27. #include <windows.h>
  28. #include <assert.h>
  29. #include "dibutil.h"
  30.  
  31.  
  32. /*************************************************************************
  33.  *
  34.  * FindDIBBits()
  35.  *
  36.  * Parameter:
  37.  *
  38.  * LPSTR lpbi       - pointer to packed-DIB memory block
  39.  *
  40.  * Return Value:
  41.  *
  42.  * LPSTR            - pointer to the DIB bits
  43.  *
  44.  * Description:
  45.  *
  46.  * This function calculates the address of the DIB's bits and returns a
  47.  * pointer to the DIB bits.
  48.  *
  49.  ************************************************************************/
  50.  
  51.  
  52. LPSTR FindDIBBits(LPSTR lpbi)
  53. {
  54.    return (lpbi + *(LPDWORD)lpbi + PaletteSize(lpbi));
  55. }
  56.  
  57.  
  58. /*************************************************************************
  59.  *
  60.  * DIBWidth()
  61.  *
  62.  * Parameter:
  63.  *
  64.  * LPSTR lpbi       - pointer to packed-DIB memory block
  65.  *
  66.  * Return Value:
  67.  *
  68.  * DWORD            - width of the DIB
  69.  *
  70.  * Description:
  71.  *
  72.  * This function gets the width of the DIB from the BITMAPINFOHEADER
  73.  * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
  74.  * width field if it is an OS/2-style DIB.
  75.  *
  76.  ************************************************************************/
  77.  
  78.  
  79. DWORD DIBWidth(LPSTR lpDIB)
  80. {
  81.    LPBITMAPINFOHEADER lpbmi;  // pointer to a Win 3.0-style DIB
  82.    LPBITMAPCOREHEADER lpbmc;  // pointer to an OS/2-style DIB
  83.  
  84.    /* point to the header (whether Win 3.0 and OS/2) */
  85.  
  86.    lpbmi = (LPBITMAPINFOHEADER)lpDIB;
  87.    lpbmc = (LPBITMAPCOREHEADER)lpDIB;
  88.  
  89.    /* return the DIB width if it is a Win 3.0 DIB */
  90.    if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))
  91.       return lpbmi->biWidth;
  92.    else  /* it is an OS/2 DIB, so return its width */
  93.       return (DWORD)lpbmc->bcWidth;
  94. }
  95.  
  96.  
  97. /*************************************************************************
  98.  *
  99.  * DIBHeight()
  100.  *
  101.  * Parameter:
  102.  *
  103.  * LPSTR lpbi       - pointer to packed-DIB memory block
  104.  *
  105.  * Return Value:
  106.  *
  107.  * DWORD            - height of the DIB
  108.  *
  109.  * Description:
  110.  *
  111.  * This function gets the height of the DIB from the BITMAPINFOHEADER
  112.  * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
  113.  * height field if it is an OS/2-style DIB.
  114.  *
  115.  ************************************************************************/
  116.  
  117.  
  118. DWORD DIBHeight(LPSTR lpDIB)
  119. {
  120.    LPBITMAPINFOHEADER lpbmi;  // pointer to a Win 3.0-style DIB
  121.    LPBITMAPCOREHEADER lpbmc;  // pointer to an OS/2-style DIB
  122.  
  123.    /* point to the header (whether OS/2 or Win 3.0 */
  124.  
  125.    lpbmi = (LPBITMAPINFOHEADER)lpDIB;
  126.    lpbmc = (LPBITMAPCOREHEADER)lpDIB;
  127.  
  128.    /* return the DIB height if it is a Win 3.0 DIB */
  129.    if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))
  130.       return lpbmi->biHeight;
  131.    else  /* it is an OS/2 DIB, so return its height */
  132.       return (DWORD)lpbmc->bcHeight;
  133. }
  134.  
  135.  
  136. /*************************************************************************
  137.  *
  138.  * PaletteSize()
  139.  *
  140.  * Parameter:
  141.  *
  142.  * LPSTR lpbi       - pointer to packed-DIB memory block
  143.  *
  144.  * Return Value:
  145.  *
  146.  * WORD             - size of the color palette of the DIB
  147.  *
  148.  * Description:
  149.  *
  150.  * This function gets the size required to store the DIB's palette by
  151.  * multiplying the number of colors by the size of an RGBQUAD (for a
  152.  * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an OS/2-
  153.  * style DIB).
  154.  *
  155.  ************************************************************************/
  156.  
  157.  
  158. WORD PaletteSize(LPSTR lpbi)
  159. {
  160.    /* calculate the size required by the palette */
  161.    if (IS_WIN30_DIB (lpbi))
  162.       return (DIBNumColors(lpbi) * sizeof(RGBQUAD));
  163.    else
  164.       return (DIBNumColors(lpbi) * sizeof(RGBTRIPLE));
  165. }
  166.  
  167.  
  168. /*************************************************************************
  169.  *
  170.  * DIBNumColors()
  171.  *
  172.  * Parameter:
  173.  *
  174.  * LPSTR lpbi       - pointer to packed-DIB memory block
  175.  *
  176.  * Return Value:
  177.  *
  178.  * WORD             - number of colors in the color table
  179.  *
  180.  * Description:
  181.  *
  182.  * This function calculates the number of colors in the DIB's color table
  183.  * by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style
  184.  * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
  185.  * if 24, no colors in color table.
  186.  *
  187.  ************************************************************************/
  188.  
  189.  
  190. WORD DIBNumColors(LPSTR lpbi)
  191. {
  192.    WORD wBitCount;  // DIB bit count
  193.  
  194.    /*  If this is a Windows-style DIB, the number of colors in the
  195.     *  color table can be less than the number of bits per pixel
  196.     *  allows for (i.e. lpbi->biClrUsed can be set to some value).
  197.     *  If this is the case, return the appropriate value.
  198.     */
  199.  
  200.    if (IS_WIN30_DIB(lpbi))
  201.    {
  202.       DWORD dwClrUsed;
  203.  
  204.       dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
  205.       if (dwClrUsed)
  206.          return (WORD)dwClrUsed;
  207.    }
  208.  
  209.    /*  Calculate the number of colors in the color table based on
  210.     *  the number of bits per pixel for the DIB.
  211.     */
  212.    if (IS_WIN30_DIB(lpbi))
  213.       wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
  214.    else
  215.       wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
  216.  
  217.    /* return number of colors based on bits per pixel */
  218.    switch (wBitCount)
  219.       {
  220.    case 1:
  221.       return 2;
  222.  
  223.    case 4:
  224.       return 16;
  225.  
  226.    case 8:
  227.       return 256;
  228.  
  229.    default:
  230.       return 0;
  231.       }
  232. }
  233.  
  234.  
  235. /*************************************************************************
  236.  *
  237.  * CreateDIBPalette()
  238.  *
  239.  * Parameter:
  240.  *
  241.  * HDIB hDIB        - specifies the DIB
  242.  *
  243.  * Return Value:
  244.  *
  245.  * HPALETTE         - specifies the palette
  246.  *
  247.  * Description:
  248.  *
  249.  * This function creates a palette from a DIB by allocating memory for the
  250.  * logical palette, reading and storing the colors from the DIB's color table
  251.  * into the logical palette, creating a palette from this logical palette,
  252.  * and then returning the palette's handle. This allows the DIB to be
  253.  * displayed using the best possible colors (important for DIBs with 256 or
  254.  * more colors).
  255.  *
  256.  ************************************************************************/
  257.  
  258.  
  259. HPALETTE CreateDIBPalette(HDIB hDIB)
  260. {
  261.    LPLOGPALETTE lpPal;      // pointer to a logical palette
  262.    HANDLE hLogPal;          // handle to a logical palette
  263.    HPALETTE hPal = NULL;    // handle to a palette
  264.    int i, wNumColors;       // loop index, number of colors in color table
  265.    LPSTR lpbi;              // pointer to packed-DIB
  266.    LPBITMAPINFO lpbmi;      // pointer to BITMAPINFO structure (Win3.0)
  267.    LPBITMAPCOREINFO lpbmc;  // pointer to BITMAPCOREINFO structure (OS/2)
  268.    BOOL bWinStyleDIB;       // flag which signifies whether this is a Win3.0 DIB
  269.  
  270.    /* if handle to DIB is invalid, return NULL */
  271.  
  272.    if (!hDIB)
  273.       return NULL;
  274.  
  275.    /* lock DIB memory block and get a pointer to it */
  276.    lpbi = GlobalLock(hDIB);
  277.  
  278.    /* get pointer to BITMAPINFO (Win 3.0) */
  279.    lpbmi = (LPBITMAPINFO)lpbi;
  280.  
  281.    /* get pointer to BITMAPCOREINFO (OS/2 1.x) */
  282.    lpbmc = (LPBITMAPCOREINFO)lpbi;
  283.  
  284.    /* get the number of colors in the DIB */
  285.    wNumColors = DIBNumColors(lpbi);
  286.  
  287.    /* is this a Win 3.0 DIB? */
  288.    bWinStyleDIB = IS_WIN30_DIB(lpbi);
  289.    if (wNumColors)
  290.    {
  291.       /* allocate memory block for logical palette */
  292.       hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) *
  293.                             wNumColors);
  294.  
  295.       /* if not enough memory, clean up and return NULL */
  296.       if (!hLogPal)
  297.       {
  298.          GlobalUnlock(hDIB);
  299.          return NULL;
  300.       }
  301.  
  302.       /* lock memory block and get pointer to it */
  303.       lpPal = (LPLOGPALETTE)GlobalLock(hLogPal);
  304.  
  305.       /* set version and number of palette entries */
  306.       lpPal->palVersion = PALVERSION;
  307.       lpPal->palNumEntries = wNumColors;
  308.  
  309.       /*  store RGB triples (if Win 3.0 DIB) or RGB quads (if OS/2 DIB)
  310.        *  into palette
  311.        */
  312.       for (i = 0; i < wNumColors; i++)
  313.       {
  314.          if (bWinStyleDIB)
  315.          {
  316.             lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
  317.             lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
  318.             lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
  319.             lpPal->palPalEntry[i].peFlags = 0;
  320.          }
  321.          else
  322.          {
  323.             lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
  324.             lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
  325.             lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
  326.             lpPal->palPalEntry[i].peFlags = 0;
  327.          }
  328.       }
  329.  
  330.       /* create the palette and get handle to it */
  331.       hPal = CreatePalette(lpPal);
  332.  
  333.       /* if error getting handle to palette, clean up and return NULL */
  334.       if (!hPal)
  335.       {
  336.          GlobalUnlock(hLogPal);
  337.          GlobalFree(hLogPal);
  338.          return NULL;
  339.       }
  340.    }
  341.  
  342.    /* clean up */
  343.    GlobalUnlock(hLogPal);
  344.    GlobalFree(hLogPal);
  345.    GlobalUnlock(hDIB);
  346.  
  347.    /* return handle to DIB's palette */
  348.    return hPal;
  349. }
  350.  
  351.  
  352. /*************************************************************************
  353.  *
  354.  * DIBToBitmap()
  355.  *
  356.  * Parameters:
  357.  *
  358.  * HDIB hDIB        - specifies the DIB to convert
  359.  *
  360.  * HPALETTE hPal    - specifies the palette to use with the bitmap
  361.  *
  362.  * Return Value:
  363.  *
  364.  * HBITMAP          - identifies the device-dependent bitmap
  365.  *
  366.  * Description:
  367.  *
  368.  * This function creates a bitmap from a DIB using the specified palette.
  369.  * If no palette is specified, default is used.
  370.  *
  371.  ************************************************************************/
  372.  
  373.  
  374. HBITMAP DIBToBitmap(HDIB hDIB, HPALETTE hPal)
  375. {
  376.    LPSTR lpDIBHdr, lpDIBBits;  // pointer to DIB header, pointer to DIB bits
  377.    HBITMAP hBitmap;            // handle to device-dependent bitmap
  378.    HDC hDC;                    // handle to DC
  379.    HPALETTE hOldPal = NULL;      // handle to a palette
  380.  
  381.    /* if invalid handle, return NULL */
  382.  
  383.    if (!hDIB)
  384.       return NULL;
  385.  
  386.    /* lock memory block and get a pointer to it */
  387.    lpDIBHdr = GlobalLock(hDIB);
  388.  
  389.    /* get a pointer to the DIB bits */
  390.    lpDIBBits = FindDIBBits(lpDIBHdr);
  391.  
  392.    /* get a DC */
  393.    hDC = GetDC(NULL);
  394.    if (!hDC)
  395.    {
  396.       /* clean up and return NULL */
  397.       GlobalUnlock(hDIB);
  398.       return NULL;
  399.    }
  400.  
  401.    /* select and realize palette */
  402.    if (hPal)
  403.       hOldPal = SelectPalette(hDC, hPal, FALSE);
  404.    RealizePalette(hDC);
  405.  
  406.    /* create bitmap from DIB info. and bits */
  407.    hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT,
  408.                             lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS)
  409.    ;
  410.  
  411.    /* restore previous palette */
  412.    if (hOldPal)
  413.       SelectPalette(hDC, hOldPal, FALSE);
  414.  
  415.    /* clean up */
  416.    ReleaseDC(NULL, hDC);
  417.    GlobalUnlock(hDIB);
  418.  
  419.    /* return handle to the bitmap */
  420.    return hBitmap;
  421. }
  422.  
  423.  
  424. /*************************************************************************
  425.  *
  426.  * BitmapToDIB()
  427.  *
  428.  * Parameters:
  429.  *
  430.  * HBITMAP hBitmap  - specifies the bitmap to convert
  431.  *
  432.  * HPALETTE hPal    - specifies the palette to use with the bitmap
  433.  *
  434.  * Return Value:
  435.  *
  436.  * HDIB             - identifies the device-dependent bitmap
  437.  *
  438.  * Description:
  439.  *
  440.  * This function creates a DIB from a bitmap using the specified palette.
  441.  *
  442.  ************************************************************************/
  443.  
  444.  
  445. HDIB BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal)
  446. {
  447.    BITMAP bm;                   // bitmap structure
  448.    BITMAPINFOHEADER bi;         // bitmap header
  449.    BITMAPINFOHEADER FAR *lpbi;  // pointer to BITMAPINFOHEADER
  450.    DWORD dwLen;                 // size of memory block
  451.    HANDLE hDIB, h;              // handle to DIB, temp handle
  452.    HDC hDC;                     // handle to DC
  453.    WORD biBits;                 // bits per pixel
  454.  
  455.    /* check if bitmap handle is valid */
  456.  
  457.    if (!hBitmap)
  458.       return NULL;
  459.  
  460.    /* if no palette is specified, use default palette */
  461.    if (hPal == NULL)
  462.       hPal = GetStockObject(DEFAULT_PALETTE);
  463.  
  464.    /* fill in BITMAP structure */
  465.    GetObject(hBitmap, sizeof(bm), (LPSTR)&bm);
  466.  
  467.    /* calculate bits per pixel */
  468.    biBits = bm.bmPlanes * bm.bmBitsPixel;
  469.  
  470.    /* initialize BITMAPINFOHEADER */
  471.    bi.biSize = sizeof(BITMAPINFOHEADER);
  472.    bi.biWidth = bm.bmWidth;
  473.    bi.biHeight = bm.bmHeight;
  474.    bi.biPlanes = 1;
  475.    bi.biBitCount = biBits;
  476.    bi.biCompression = DIB_RGB_COLORS;
  477.    bi.biSizeImage = 0;
  478.    bi.biXPelsPerMeter = 0;
  479.    bi.biYPelsPerMeter = 0;
  480.    bi.biClrUsed = 0;
  481.    bi.biClrImportant = 0;
  482.  
  483.    /* calculate size of memory block required to store BITMAPINFO */
  484.    dwLen = bi.biSize + PaletteSize((LPSTR)&bi);
  485.  
  486.    /* get a DC */
  487.    hDC = GetDC(NULL);
  488.  
  489.    /* select and realize our palette */
  490.    hPal = SelectPalette(hDC, hPal, FALSE);
  491.    RealizePalette(hDC);
  492.  
  493.    /* alloc memory block to store our bitmap */
  494.    hDIB = GlobalAlloc(GHND, dwLen);
  495.  
  496.    /* if we couldn't get memory block */
  497.    if (!hDIB)
  498.    {
  499.       /* clean up and return NULL */
  500.       SelectPalette(hDC, hPal, TRUE);
  501.       RealizePalette(hDC);
  502.       ReleaseDC(NULL, hDC);
  503.       return NULL;
  504.    }
  505.  
  506.    /* lock memory and get pointer to it */
  507.    lpbi = (VOID FAR *)GlobalLock(hDIB);
  508.  
  509.    /* use our bitmap info. to fill BITMAPINFOHEADER */
  510.    *lpbi = bi;
  511.  
  512.    /*  call GetDIBits with a NULL lpBits param, so it will calculate the
  513.     *  biSizeImage field for us
  514.     */
  515.    GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, NULL, (LPBITMAPINFO)lpbi,
  516.              DIB_RGB_COLORS);
  517.  
  518.    /* get the info. returned by GetDIBits and unlock memory block */
  519.    bi = *lpbi;
  520.    GlobalUnlock(hDIB);
  521.  
  522.    /* if the driver did not fill in the biSizeImage field, make one up */
  523.    if (bi.biSizeImage == 0)
  524.       bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
  525.  
  526.    /* realloc the buffer big enough to hold all the bits */
  527.    dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage;
  528.    if (h = GlobalReAlloc(hDIB, dwLen, 0))
  529.       hDIB = h;
  530.    else
  531.    {
  532.       /* clean up and return NULL */
  533.       GlobalFree(hDIB);
  534.       hDIB = NULL;
  535.       SelectPalette(hDC, hPal, TRUE);
  536.       RealizePalette(hDC);
  537.       ReleaseDC(NULL, hDC);
  538.       return NULL;
  539.    }
  540.  
  541.    /* lock memory block and get pointer to it */
  542.    lpbi = (VOID FAR *)GlobalLock(hDIB);
  543.  
  544.    /*  call GetDIBits with a NON-NULL lpBits param, and actualy get the
  545.     *  bits this time
  546.     */
  547.    if (GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, (LPSTR)lpbi + (WORD)lpbi
  548.                  ->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi,
  549.                  DIB_RGB_COLORS) == 0)
  550.    {
  551.       /* clean up and return NULL */
  552.       GlobalUnlock(hDIB);
  553.       hDIB = NULL;
  554.       SelectPalette(hDC, hPal, TRUE);
  555.       RealizePalette(hDC);
  556.       ReleaseDC(NULL, hDC);
  557.       return NULL;
  558.    }
  559.    bi = *lpbi;
  560.  
  561.    /* clean up */
  562.    GlobalUnlock(hDIB);
  563.    SelectPalette(hDC, hPal, TRUE);
  564.    RealizePalette(hDC);
  565.    ReleaseDC(NULL, hDC);
  566.  
  567.    /* return handle to the DIB */
  568.    return hDIB;
  569. }
  570.  
  571.  
  572. /*************************************************************************
  573.  *
  574.  * PalEntriesOnDevice()
  575.  *
  576.  * Parameter:
  577.  *
  578.  * HDC hDC          - device context
  579.  *
  580.  * Return Value:
  581.  *
  582.  * int              - number of palette entries on device
  583.  *
  584.  * Description:
  585.  *
  586.  * This function gets the number of palette entries on the specified device
  587.  *
  588.  ************************************************************************/
  589.  
  590.  
  591. int PalEntriesOnDevice(HDC hDC)
  592. {
  593.    int nColors;  // number of colors
  594.  
  595.    /*  Find out the number of palette entries on this
  596.     *  device.
  597.     */
  598.  
  599.    nColors = GetDeviceCaps(hDC, SIZEPALETTE);
  600.  
  601.    /*  For non-palette devices, we'll use the # of system
  602.     *  colors for our palette size.
  603.     */
  604.    if (!nColors)
  605.       nColors = GetDeviceCaps(hDC, NUMCOLORS);
  606.    assert(nColors);
  607.    return nColors;
  608. }
  609.  
  610.  
  611. /*************************************************************************
  612.  *
  613.  * DIBHeight()
  614.  *
  615.  * Parameter:
  616.  *
  617.  * LPSTR lpbi       - pointer to packed-DIB memory block
  618.  *
  619.  * Return Value:
  620.  *
  621.  * DWORD            - height of the DIB
  622.  *
  623.  * Description:
  624.  *
  625.  * This function returns a handle to a palette which represents the system
  626.  * palette (each entry is an offset into the system palette instead of an
  627.  * RGB with a flag of PC_EXPLICIT).
  628.  *
  629.  ************************************************************************/
  630.  
  631.  
  632. HPALETTE GetSystemPalette(void)
  633. {
  634.    HDC hDC;                // handle to a DC
  635.    HPALETTE hPal = NULL;   // handle to a palette
  636.    HANDLE hLogPal;         // handle to a logical palette
  637.    LPLOGPALETTE lpLogPal;  // pointer to a logical palette
  638.    int i, nColors;         // loop index, number of colors
  639.  
  640.    /* Find out how many palette entries we want. */
  641.  
  642.    hDC = GetDC(NULL);
  643.    if (!hDC)
  644.       return NULL;
  645.    nColors = PalEntriesOnDevice(hDC);
  646.    ReleaseDC(NULL, hDC);
  647.  
  648.    /* Allocate room for the palette and lock it. */
  649.    hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors * sizeof(
  650.                          PALETTEENTRY));
  651.  
  652.    /* if we didn't get a logical palette, return NULL */
  653.    if (!hLogPal)
  654.       return NULL;
  655.  
  656.    /* get a pointer to the logical palette */
  657.    lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal);
  658.  
  659.    /* set some important fields */
  660.    lpLogPal->palVersion = PALVERSION;
  661.    lpLogPal->palNumEntries = nColors;
  662.    for (i = 0; i < nColors; i++)
  663.    {
  664.       lpLogPal->palPalEntry[i].peBlue = 0;
  665.       *((LPWORD)(&lpLogPal->palPalEntry[i].peRed)) = i;
  666.       lpLogPal->palPalEntry[i].peFlags = PC_EXPLICIT;
  667.    }
  668.  
  669.    /*  Go ahead and create the palette.  Once it's created,
  670.     *  we no longer need the LOGPALETTE, so free it.
  671.     */
  672.    hPal = CreatePalette(lpLogPal);
  673.  
  674.    /* clean up */
  675.    GlobalUnlock(hLogPal);
  676.    GlobalFree(hLogPal);
  677.    return hPal;
  678. }
  679.